
#include <BFont>
#include <BShortcut>
#include "member_BMenu.h"
#include "member_BWidget.h"

using namespace BWE;

member_BMenu::member_BMenu(BMenu* menu)
{
	boss = menu;
	align = Align_LeftCenter;
	form = Form_None;
	spacing = 1;
	orientation = Orientation_Vertical;
	arrowAlign = Align_Center;
	arrowGraph = Graph_Arrow_Right;
	separatorSize = 1;
	separatorStyle = 0;
	shortcutVisible = true;
	shortcutSpacing = 0;
	shortcutStyle = 0;

	dirty = false;
	pressed = false;
	expanded = true;
	hoverIndex = -1;
}
member_BMenu::~member_BMenu()
{

}

void member_BMenu::raiseSignal(int signal, const BValue& value)
{
	BMenu* menu = boss;
	while (menu)
	{
		menu->emit(signal, value);
		menu = dynamic_cast<BMenu*>(widget_member(menu)->parent);
	}
}

BMenu* member_BMenu::locateMenu(const BString& path, BString& temp)
{
	if (path.contain('/'))
	{
		int pos = 0;
		int end = 0;
		end = path.find('/', pos);
		BMenu* menu = boss;
		while (end < path.size())
		{
			path.substr(temp, pos, end);
			menu = menu->menu(temp);
			if (!menu)
				return 0;
			pos = end + 1;
			end = path.find('/', pos);
		}
		path.substr(temp, pos, end);
		return menu;
	}
	return 0;
}

void member_BMenu::freshRects()
{
	const BStyle* style = boss->realStyle();
	const BFont* font = boss->realFont();
	const BFont* shortcutFont = 0;
	if (shortcutStyle)
		shortcutFont = shortcutStyle->font();
	if (!shortcutFont)
		shortcutFont = font;

	BSize realArrowSize = arrowSize;
	if (realArrowSize.width() < 1)
		realArrowSize.width() = font->size();
	if (realArrowSize.height() < 1)
		realArrowSize.height() = font->size();

	int expandSpacing = shortcutSpacing;
	if (expandSpacing < 1)
		expandSpacing = font->size();
	BSize expandSize = realArrowSize.width();
	for (int i = 0; i < items.size(); i++)
	{
		IMenuItem& item = items[i];
		if (item.dirtyStyle)
		{
			item.form = form;
			item.align = align;
			item.spacing = spacing;
			item.dispenseStyles(style);
			item.applyStyle(style);
			item.dirtyStyle = false;
			item.dirty = true;
		}
		if (shortcutVisible && item.action && item.action->shortcut())
		{
			BShortcut* shortcut = item.action->shortcut();
			item.shortcutSize = shortcutFont->textSize(shortcut->text());
			if (item.hintSize.height() < item.shortcutSize.height())
				item.hintSize.height() = item.shortcutSize.height();
		}
		if (expandSize.width() < item.shortcutSize.width())
			expandSize.width() = item.shortcutSize.width();
		if (expandSize.height() < item.shortcutSize.height())
			expandSize.height() = item.shortcutSize.height();
	}

	BRect crect = boss->centerRect();
	int width = 0;
	int height = 0;
	if (orientation == Orientation_Vertical)
	{
		for (int i = 0; i < items.size(); i++)
		{
			IMenuItem& item = items[i];
			if (item.action && !item.action->visible())
				continue;
			if (item.empty())
			{
				item.hintSize = separatorSize;
			}
			else if (item.dirty)
			{
				item.freshSize(font, 0);
				item.dirty = false;
			}
			item.expandSize = expandSize;
			width = bMax(width, item.hintSize.width() + expandSpacing + expandSize.width());
			height += item.hintSize.height() + spacing;
		}
		height -= spacing;
		int posX = crect.x();
		int posY = crect.y();
		for (int i = 0; i < items.size(); i++)
		{
			IMenuItem& item = items[i];
			if (item.action && !item.action->visible())
				continue;
			item.pos.set(posX, posY);
			item.setSize(crect.width(), item.hintSize.height());
			BRect arrowArea = item.rect();
			arrowArea.left() = item.rect().right() - realArrowSize.width();
			item.arrowRect = arrowArea.align(arrowAlign, realArrowSize);
			posY += item.hintSize.height() + spacing;
		}
	}
	if (orientation == Orientation_Horizontal)
	{
		for (int i = 0; i < items.size(); i++)
		{
			IMenuItem& item = items[i];
			if (item.action && !item.action->visible())
				continue;
			if (item.empty())
			{
				item.hintSize = separatorSize;
			}
			else if (item.dirty)
			{
				item.freshSize(font, 0);
				item.dirty = false;
			}
			height = bMax(height, item.hintSize.height() + spacing + realArrowSize.height());
			width += item.hintSize.width() + spacing;
		}
		width -= spacing;
		int posX = crect.x();
		int posY = crect.y();
		for (int i = 0; i < items.size(); i++)
		{
			IMenuItem& item = items[i];
			if (item.action && !item.action->visible())
				continue;
			item.pos.set(posX, posY);
			item.setSize(item.hintSize.width(), crect.height());
			BRect arrowArea = item.rect();
			arrowArea.left() = item.rect().right() - realArrowSize.width();
			item.arrowRect = arrowArea.align(arrowAlign, realArrowSize);
			posX += item.hintSize.width() + spacing;
		}
	}
	contentSize.set(width, height);
}

void member_BMenu::slotActionRenamed(BObject* object, const BValue& value)
{
	for (int i = 0; i < items.size(); i++)
	{
		if (items[i].action == object)
		{
			dirty = true;
			items[i].dirty = true;
			boss->fresh();
			break;
		}
	}
}
void member_BMenu::slotActionEnabled(BObject* object, const BValue& value)
{
	boss->fresh();
}
void member_BMenu::slotActionIconChanged(BObject* object, const BValue& value)
{
	for (int i = 0; i < items.size(); i++)
	{
		if (items[i].action == object)
		{
			dirty = true;
			items[i].dirty = true;
			boss->fresh();
			break;
		}
	}
}
void member_BMenu::slotActionTextChanged(BObject* object, const BValue& value)
{
	for (int i = 0; i < items.size(); i++)
	{
		if (items[i].action == object)
		{
			dirty = true;
			items[i].dirty = true;
			boss->fresh();
			break;
		}
	}
}
void member_BMenu::slotActionChecked(BObject* object, const BValue& value)
{
	BAction* action = (BAction*)object;
	raiseSignal(Signal_Checked, action);
	boss->fresh();
}
void member_BMenu::slotActionTriggered(BObject* object, const BValue& value)
{
	BAction* action = (BAction*)object;
	raiseSignal(Signal_Triggered, action);
	boss->finish(action);
}
void member_BMenu::slotActionVisibleChanged(BObject* object, const BValue& value)
{
	dirty = true;
	boss->fresh();
}

void member_BMenu::slotMenuEnabled(BObject* object, const BValue& value)
{
	boss->fresh();
}
void member_BMenu::slotMenuRenamed(BObject* object, const BValue& value)
{
	for (int i = 0; i < items.size(); i++)
	{
		if (items[i].menu == object)
		{
			dirty = true;
			items[i].dirty = true;
			boss->fresh();
			break;
		}
	}
}
void member_BMenu::slotMenuStyled(BObject* object, const BValue& value)
{
	for (int i = 0; i < items.size(); i++)
	{
		if (items[i].menu == object)
		{
			dirty = true;
			items[i].dirty = true;
			boss->fresh();
			break;
		}
	}
}
void member_BMenu::slotMenuIconChanged(BObject* object, const BValue& value)
{
	for (int i = 0; i < items.size(); i++)
	{
		if (items[i].menu == object)
		{
			dirty = true;
			items[i].dirty = true;
			boss->fresh();
			break;
		}
	}
}
void member_BMenu::slotMenuTitleChanged(BObject* object, const BValue& value)
{
	for (int i = 0; i < items.size(); i++)
	{
		if (items[i].menu == object)
		{
			dirty = true;
			items[i].dirty = true;
			boss->fresh();
			break;
		}
	}
}
void member_BMenu::slotMenuVisibleChanged(BObject* object, const BValue& value)
{
	dirty = true;
	boss->fresh();
}
